{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50 | Batch 0/77 | train_loss: 3.399 | test_loss: 3.393\n",
      "Epoch 1/50 | Batch 50/77 | train_loss: 2.782 | test_loss: 2.749\n",
      "Epoch 2/50 | Batch 0/77 | train_loss: 2.390 | test_loss: 2.369\n",
      "Epoch 2/50 | Batch 50/77 | train_loss: 1.960 | test_loss: 1.920\n",
      "Epoch 3/50 | Batch 0/77 | train_loss: 1.788 | test_loss: 1.752\n",
      "Epoch 3/50 | Batch 50/77 | train_loss: 1.510 | test_loss: 1.495\n",
      "Epoch 4/50 | Batch 0/77 | train_loss: 1.421 | test_loss: 1.396\n",
      "Epoch 4/50 | Batch 50/77 | train_loss: 1.233 | test_loss: 1.228\n",
      "Epoch 5/50 | Batch 0/77 | train_loss: 1.162 | test_loss: 1.155\n",
      "Epoch 5/50 | Batch 50/77 | train_loss: 1.018 | test_loss: 1.007\n",
      "Epoch 6/50 | Batch 0/77 | train_loss: 0.955 | test_loss: 0.943\n",
      "Epoch 6/50 | Batch 50/77 | train_loss: 0.838 | test_loss: 0.814\n",
      "Epoch 7/50 | Batch 0/77 | train_loss: 0.771 | test_loss: 0.762\n",
      "Epoch 7/50 | Batch 50/77 | train_loss: 0.688 | test_loss: 0.654\n",
      "Epoch 8/50 | Batch 0/77 | train_loss: 0.618 | test_loss: 0.618\n",
      "Epoch 8/50 | Batch 50/77 | train_loss: 0.567 | test_loss: 0.536\n",
      "Epoch 9/50 | Batch 0/77 | train_loss: 0.504 | test_loss: 0.504\n",
      "Epoch 9/50 | Batch 50/77 | train_loss: 0.474 | test_loss: 0.442\n",
      "Epoch 10/50 | Batch 0/77 | train_loss: 0.416 | test_loss: 0.419\n",
      "Epoch 10/50 | Batch 50/77 | train_loss: 0.397 | test_loss: 0.366\n",
      "Epoch 11/50 | Batch 0/77 | train_loss: 0.341 | test_loss: 0.352\n",
      "Epoch 11/50 | Batch 50/77 | train_loss: 0.332 | test_loss: 0.305\n",
      "Epoch 12/50 | Batch 0/77 | train_loss: 0.280 | test_loss: 0.299\n",
      "Epoch 12/50 | Batch 50/77 | train_loss: 0.279 | test_loss: 0.257\n",
      "Epoch 13/50 | Batch 0/77 | train_loss: 0.232 | test_loss: 0.257\n",
      "Epoch 13/50 | Batch 50/77 | train_loss: 0.236 | test_loss: 0.218\n",
      "Epoch 14/50 | Batch 0/77 | train_loss: 0.194 | test_loss: 0.222\n",
      "Epoch 14/50 | Batch 50/77 | train_loss: 0.201 | test_loss: 0.188\n",
      "Epoch 15/50 | Batch 0/77 | train_loss: 0.165 | test_loss: 0.191\n",
      "Epoch 15/50 | Batch 50/77 | train_loss: 0.172 | test_loss: 0.163\n",
      "Epoch 16/50 | Batch 0/77 | train_loss: 0.149 | test_loss: 0.157\n",
      "Epoch 16/50 | Batch 50/77 | train_loss: 0.153 | test_loss: 0.141\n",
      "Epoch 17/50 | Batch 0/77 | train_loss: 0.122 | test_loss: 0.142\n",
      "Epoch 17/50 | Batch 50/77 | train_loss: 0.133 | test_loss: 0.123\n",
      "Epoch 18/50 | Batch 0/77 | train_loss: 0.103 | test_loss: 0.126\n",
      "Epoch 18/50 | Batch 50/77 | train_loss: 0.109 | test_loss: 0.109\n",
      "Epoch 19/50 | Batch 0/77 | train_loss: 0.089 | test_loss: 0.106\n",
      "Epoch 19/50 | Batch 50/77 | train_loss: 0.095 | test_loss: 0.097\n",
      "Epoch 20/50 | Batch 0/77 | train_loss: 0.078 | test_loss: 0.094\n",
      "Epoch 20/50 | Batch 50/77 | train_loss: 0.085 | test_loss: 0.087\n",
      "Epoch 21/50 | Batch 0/77 | train_loss: 0.067 | test_loss: 0.082\n",
      "Epoch 21/50 | Batch 50/77 | train_loss: 0.076 | test_loss: 0.077\n",
      "Epoch 22/50 | Batch 0/77 | train_loss: 0.059 | test_loss: 0.073\n",
      "Epoch 22/50 | Batch 50/77 | train_loss: 0.068 | test_loss: 0.067\n",
      "Epoch 23/50 | Batch 0/77 | train_loss: 0.053 | test_loss: 0.067\n",
      "Epoch 23/50 | Batch 50/77 | train_loss: 0.060 | test_loss: 0.061\n",
      "Epoch 24/50 | Batch 0/77 | train_loss: 0.049 | test_loss: 0.062\n",
      "Epoch 24/50 | Batch 50/77 | train_loss: 0.052 | test_loss: 0.056\n",
      "Epoch 25/50 | Batch 0/77 | train_loss: 0.044 | test_loss: 0.058\n",
      "Epoch 25/50 | Batch 50/77 | train_loss: 0.045 | test_loss: 0.050\n",
      "Epoch 26/50 | Batch 0/77 | train_loss: 0.039 | test_loss: 0.054\n",
      "Epoch 26/50 | Batch 50/77 | train_loss: 0.041 | test_loss: 0.046\n",
      "Epoch 27/50 | Batch 0/77 | train_loss: 0.035 | test_loss: 0.046\n",
      "Epoch 27/50 | Batch 50/77 | train_loss: 0.037 | test_loss: 0.042\n",
      "Epoch 28/50 | Batch 0/77 | train_loss: 0.031 | test_loss: 0.041\n",
      "Epoch 28/50 | Batch 50/77 | train_loss: 0.035 | test_loss: 0.038\n",
      "Epoch 29/50 | Batch 0/77 | train_loss: 0.028 | test_loss: 0.037\n",
      "Epoch 29/50 | Batch 50/77 | train_loss: 0.034 | test_loss: 0.034\n",
      "Epoch 30/50 | Batch 0/77 | train_loss: 0.026 | test_loss: 0.034\n",
      "Epoch 30/50 | Batch 50/77 | train_loss: 0.034 | test_loss: 0.031\n",
      "Epoch 31/50 | Batch 0/77 | train_loss: 0.024 | test_loss: 0.032\n",
      "Epoch 31/50 | Batch 50/77 | train_loss: 0.030 | test_loss: 0.031\n",
      "Epoch 32/50 | Batch 0/77 | train_loss: 0.022 | test_loss: 0.031\n",
      "Epoch 32/50 | Batch 50/77 | train_loss: 0.025 | test_loss: 0.031\n",
      "Epoch 33/50 | Batch 0/77 | train_loss: 0.020 | test_loss: 0.033\n",
      "Epoch 33/50 | Batch 50/77 | train_loss: 0.022 | test_loss: 0.030\n",
      "Epoch 34/50 | Batch 0/77 | train_loss: 0.019 | test_loss: 0.030\n",
      "Epoch 34/50 | Batch 50/77 | train_loss: 0.019 | test_loss: 0.028\n",
      "Epoch 35/50 | Batch 0/77 | train_loss: 0.020 | test_loss: 0.028\n",
      "Epoch 35/50 | Batch 50/77 | train_loss: 0.017 | test_loss: 0.025\n",
      "Epoch 36/50 | Batch 0/77 | train_loss: 0.021 | test_loss: 0.029\n",
      "Epoch 36/50 | Batch 50/77 | train_loss: 0.016 | test_loss: 0.022\n",
      "Epoch 37/50 | Batch 0/77 | train_loss: 0.016 | test_loss: 0.027\n",
      "Epoch 37/50 | Batch 50/77 | train_loss: 0.015 | test_loss: 0.020\n",
      "Epoch 38/50 | Batch 0/77 | train_loss: 0.015 | test_loss: 0.020\n",
      "Epoch 38/50 | Batch 50/77 | train_loss: 0.015 | test_loss: 0.019\n",
      "Epoch 39/50 | Batch 0/77 | train_loss: 0.015 | test_loss: 0.019\n",
      "Epoch 39/50 | Batch 50/77 | train_loss: 0.014 | test_loss: 0.019\n",
      "Epoch 40/50 | Batch 0/77 | train_loss: 0.013 | test_loss: 0.018\n",
      "Epoch 40/50 | Batch 50/77 | train_loss: 0.013 | test_loss: 0.019\n",
      "Epoch 41/50 | Batch 0/77 | train_loss: 0.012 | test_loss: 0.018\n",
      "Epoch 41/50 | Batch 50/77 | train_loss: 0.012 | test_loss: 0.018\n",
      "Epoch 42/50 | Batch 0/77 | train_loss: 0.010 | test_loss: 0.016\n",
      "Epoch 42/50 | Batch 50/77 | train_loss: 0.011 | test_loss: 0.018\n",
      "Epoch 43/50 | Batch 0/77 | train_loss: 0.010 | test_loss: 0.015\n",
      "Epoch 43/50 | Batch 50/77 | train_loss: 0.010 | test_loss: 0.018\n",
      "Epoch 44/50 | Batch 0/77 | train_loss: 0.009 | test_loss: 0.014\n",
      "Epoch 44/50 | Batch 50/77 | train_loss: 0.010 | test_loss: 0.017\n",
      "Epoch 45/50 | Batch 0/77 | train_loss: 0.008 | test_loss: 0.013\n",
      "Epoch 45/50 | Batch 50/77 | train_loss: 0.009 | test_loss: 0.015\n",
      "Epoch 46/50 | Batch 0/77 | train_loss: 0.008 | test_loss: 0.012\n",
      "Epoch 46/50 | Batch 50/77 | train_loss: 0.008 | test_loss: 0.014\n",
      "Epoch 47/50 | Batch 0/77 | train_loss: 0.007 | test_loss: 0.012\n",
      "Epoch 47/50 | Batch 50/77 | train_loss: 0.007 | test_loss: 0.013\n",
      "Epoch 48/50 | Batch 0/77 | train_loss: 0.007 | test_loss: 0.011\n",
      "Epoch 48/50 | Batch 50/77 | train_loss: 0.007 | test_loss: 0.013\n",
      "Epoch 49/50 | Batch 0/77 | train_loss: 0.007 | test_loss: 0.011\n",
      "Epoch 49/50 | Batch 50/77 | train_loss: 0.007 | test_loss: 0.012\n",
      "Epoch 50/50 | Batch 0/77 | train_loss: 0.006 | test_loss: 0.011\n",
      "Epoch 50/50 | Batch 50/77 | train_loss: 0.006 | test_loss: 0.012\n",
      "IN: c o m m o n\n",
      "OUT: c m m n o o <EOS>\n",
      "IN: a p p l e\n",
      "OUT: a e l p p <EOS>\n",
      "IN: z h e d o n g\n",
      "OUT: d e g h n o z <EOS>\n"
     ]
    }
   ],
   "source": [
    "from seq2seq import Seq2Seq\n",
    "import sys\n",
    "if int(sys.version[0]) == 2:\n",
    "    from io import open\n",
    "\n",
    "\n",
    "def read_data(path):\n",
    "    with open(path, 'r', encoding='utf-8') as f:\n",
    "        return f.read()\n",
    "# end function read_data\n",
    "\n",
    "\n",
    "def build_map(data):\n",
    "    specials = ['<GO>',  '<EOS>', '<PAD>', '<UNK>']\n",
    "    chars = list(set([char for line in data.split('\\n') for char in line]))\n",
    "    idx2char = {idx: char for idx, char in enumerate(specials + chars)}\n",
    "    char2idx = {char: idx for idx, char in idx2char.items()}\n",
    "    return idx2char, char2idx\n",
    "# end function build_map\n",
    "\n",
    "\n",
    "def preprocess_data():\n",
    "    X_data = read_data('temp/letters_source.txt')\n",
    "    Y_data = read_data('temp/letters_target.txt')\n",
    "\n",
    "    X_idx2char, X_char2idx = build_map(X_data)\n",
    "    Y_idx2char, Y_char2idx = build_map(Y_data)\n",
    "\n",
    "    x_unk = X_char2idx['<UNK>']\n",
    "    y_unk = Y_char2idx['<UNK>']\n",
    "    y_eos = Y_char2idx['<EOS>']\n",
    "\n",
    "    X_indices = [[X_char2idx.get(char, x_unk) for char in line] for line in X_data.split('\\n')]\n",
    "    Y_indices = [[Y_char2idx.get(char, y_unk) for char in line] + [y_eos] for line in Y_data.split('\\n')]\n",
    "\n",
    "    return X_indices, Y_indices, X_char2idx, Y_char2idx, X_idx2char, Y_idx2char\n",
    "# end function preprocess_data\n",
    "\n",
    "\n",
    "def main():\n",
    "    BATCH_SIZE = 128\n",
    "    X_indices, Y_indices, X_char2idx, Y_char2idx, X_idx2char, Y_idx2char = preprocess_data()\n",
    "    X_train = X_indices[BATCH_SIZE:]\n",
    "    Y_train = Y_indices[BATCH_SIZE:]\n",
    "    X_test = X_indices[:BATCH_SIZE]\n",
    "    Y_test = Y_indices[:BATCH_SIZE]\n",
    "\n",
    "    model = Seq2Seq(\n",
    "        rnn_size = 50,\n",
    "        n_layers = 2,\n",
    "        X_word2idx = X_char2idx,\n",
    "        encoder_embedding_dim = 15,\n",
    "        Y_word2idx = Y_char2idx,\n",
    "        decoder_embedding_dim = 15,\n",
    "    )\n",
    "    model.fit(X_train, Y_train, val_data=(X_test, Y_test), batch_size=BATCH_SIZE, n_epoch=50)\n",
    "    model.infer('common', X_idx2char, Y_idx2char)\n",
    "    model.infer('apple', X_idx2char, Y_idx2char)\n",
    "    model.infer('zhedong', X_idx2char, Y_idx2char)\n",
    "# end function main\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
